package com.chisheng.caa.util;

import com.chisheng.caa.pojo.Bean;
import com.chisheng.caa.pojo.DuplicateStrategy;
import com.chisheng.caa.pojo.LoadingStrategy;
import lombok.SneakyThrows;
import org.springframework.lang.Nullable;
import com.chisheng.caa.exception.DuplicateValueException;

import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Map 工具类
 */
public final class MapUtil {

    private MapUtil() {
        throw new UnsupportedOperationException();
    }

    /**
     * 策略 put 方法
     *
     * @param beanMap  目标集合
     * @param bean     元素
     * @param strategy 重复处理策略
     * @param <T>      元素类型
     */
    @SneakyThrows
    public static <T extends Bean> void put(Map<String, T> beanMap, T bean, DuplicateStrategy strategy) {
        String key = bean.getKey();
        if (beanMap.containsKey(key)) {
            T dest = beanMap.get(key);
            switch (strategy) {
                case DO_NOT_CARE:
                    return;
                case NOT_ALLOWED:
                    throw new DuplicateValueException(String.format("重复值 '%s'", key));
                case FORWARD_INTEGRATION:
                    BeanUtil.copyProperties(bean, dest, BeanUtil.nonnullProperties(dest));
                    break;
                case BACKWARD_INTEGRATION:
                    BeanUtil.copyProperties(bean, dest, true);
                    break;
                default:
                    throw new IllegalArgumentException();
            }
        }

        @SuppressWarnings("unchecked")
        T dest = (T) BeanUtil.copyProperties(bean, bean.getClass());
        beanMap.put(key, dest);
    }

    /**
     * 策略 putAll
     *
     * @param beanMap           目标集合
     * @param beanColl          元素集
     * @param loadingStrategy   导入策略
     * @param duplicateStrategy 重复处理策略
     * @param <T>               元素类型
     */
    public static <T extends Bean> void putAll(Map<String, T> beanMap, Collection<T> beanColl, LoadingStrategy loadingStrategy, @Nullable DuplicateStrategy duplicateStrategy) {
        if (Objects.equals(loadingStrategy, LoadingStrategy.OVERWRITE)) {
            beanMap.clear();
            beanMap.putAll(beanColl.stream().collect(Collectors.toMap(Bean::getKey, v -> v)));
        } else if (Objects.equals(loadingStrategy, LoadingStrategy.APPEND)) {
            Objects.requireNonNull(duplicateStrategy);
            beanColl.forEach(bean -> put(beanMap, bean, duplicateStrategy));
        } else {
            throw new IllegalArgumentException(String.format("非法参数值 '%s'", loadingStrategy));
        }
    }

}
